home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 July / Macworld (1999-07).dmg / Shareware World / Info / For Developers / Mops 3.4.sea / Mops source / PPC source / cg2 < prev    next >
Text File  |  1998-11-06  |  45KB  |  1,685 lines

  1. marker m__cg2
  2.  
  3.  
  4. PPC?
  5. [IF]
  6. false    constant    debug?
  7. false    constant    cascadeTest?
  8. [ELSE]
  9. false    constant    debug?
  10. false    constant    cascadeTest?
  11. [THEN]
  12.  
  13.  
  14. (* This file handles the basic arithmetic and logical stuff, including
  15.    optimizations such as cascading (combining arithmetic ops) and strength
  16.    reduction.  Also branch resolution.
  17. *)
  18.  
  19.  
  20. (*
  21. CASCADE&MATCH? is called if we have an op which could possibly be combined with
  22. a preceding op - such a literal add where the other operand was also a literal
  23. add.  If it makes sense to combine the ops into a single op we do so, by deleting
  24. the earlier op and suitably modifying the new one.  After this we check for a
  25. match with a value already in the regs.  If there's a match, we generate a new
  26. reference to the matching op (and so generate no code).  In this case we return
  27. true to show that there's nothing more to do.  Otherwise we return false.
  28. Note that a false return doesn't mean we didn't do a cascade - but in this case
  29. we completely handle the cascade here so don't need to notify the caller.
  30.  
  31. On entry the new op we're looking at is in theOD.  (We do it this way because
  32. we mightn't have allocated a register for it yet.)  In the case where one operand
  33. is literal, it's always in B_opnd of theOD.  If this is a fetch or store, it will
  34. actually be zero.
  35.  
  36. We also assume references to the operands are in opnd1 and opnd2.  The idea of this
  37. is that if we cascade or in some way change the operand reg(s), we'll change the
  38. corresponding reference, so the caller will free: the right reg when it's finished.
  39. *)
  40.  
  41.  
  42. 0    value    antec#        \ the reg# of the operand of the antecedent op, which
  43.                         \  might be deleted if we cascade.
  44.  
  45.  
  46. \ OK_for_cascade? runs a series of checks on the GPR whose number is in antec#,
  47. \  to see if a cascade is safe.  It returns the appropriate flag.
  48.  
  49. objPtr    cas_regs  class_is ODs_class
  50.  
  51. : OK_FOR_CASCADE?  { \ antecedentCDP -- b }
  52.  
  53.     antec# select: cas_regs            \ select the operand GPR
  54.     get: ivar> opCDP in cas_regs  -> antecedentCDP
  55.  
  56.     false
  57.  
  58.     cascadeTest? if
  59.         ." ok_for_cascade? called on:"  print: cas_regs  cr
  60.     then
  61.  
  62. \ we won't cascade if it would cross a basic block boundary - this would
  63. \  bristle with problems, so isn't worth worrying about.  But note we
  64. \  ignore backstop_CDP here, since we're not doing any hoisting so 
  65. \  checking for a BB boundary is sufficient.  This also allows
  66. \  cascading to work at the start of defns, where the initial regs have
  67. \  zero in their opCDP fields, since we initialize basic_block_start to
  68. \  zero at the start of defns.
  69.  
  70.     get: ivar> opCDP in cas_regs  basic_block_start  u< ?EXIT
  71.  
  72. \ we can't cascade an op on a special reg - if it is, presumably
  73. \  we need the result and can't tamper with it, regardless of its refcnt.
  74.  
  75.     get: ivar> special? in cas_regs  ?EXIT
  76.  
  77. \ and we can't cascade if the operand's refcnt is > 1 (which is *this* ref) - if
  78. \  there are any others, we need that result, so mustn't clobber that op.
  79.  
  80.     get: ivar> refcnt in cas_regs  1 > ?EXIT
  81.  
  82. \ and we can't cascade if there was another use of that reg between its op and
  83. \  here - this is the same as an extra ref, except that it's already been retired.
  84.  
  85.     get: ivar> lastRefCDP in cas_regs
  86.     get: ivar> opCDP in cas_regs  u>  ?EXIT
  87.  
  88. \ and we can't cascade if one of the antecedent's operand regs has changed
  89. \  between there and here, which would prevent us validly recompiling here.
  90.  
  91.     Atype: cas_regs  gprRef =
  92.     IF    Agpr: cas_regs  select: cas_regs
  93.         get: ivar> opCDP in cas_regs
  94.         antecedentCDP u>
  95.         antec# select: cas_regs                \ restore selection
  96.         ?EXIT
  97.     THEN
  98.     
  99.     Btype: cas_regs  GPRRef =
  100.     IF    Bgpr: cas_regs  select: cas_regs
  101.         get: ivar> opCDP in cas_regs
  102.         antecedentCDP u>
  103.         antec# select: cas_regs                \ restore selection
  104.         ?EXIT
  105.     THEN
  106.  
  107. \ if we got here, it's OK!
  108.  
  109.     drop  true
  110. ;
  111.  
  112.  
  113. : CanBeMask?  { litVal \ mEnd ones? n -- mBegin mEnd true  | -- false }
  114.  
  115.     litVal NIF  0 0  true  EXIT  THEN
  116.     litVal -1 = IF  0 31 true  EXIT  THEN        \ they're the easy ones
  117.  
  118.     false -> ones?        \ nothing scanned yet, or just 0's
  119.     31 -> n
  120.     BEGIN    litVal
  121.     WHILE    litVal 1 and
  122.             NIF                \ next bit is a zero
  123.                 ones?
  124.                 IF            \ we were scanning ones and got a zero.  There
  125.                             \  must be more ones left (or we wouldn't have
  126.                             \  continued the loop).  So it's not a mask.
  127.                     false  EXIT
  128.                 THEN
  129.             ELSE            \ next bit is a one
  130.                 ones?
  131.                 NIF            \ we were scanning zeros and got a 1.  Must be the
  132.                             \  first one, so we mark its position.
  133.                     n -> mEnd  true -> ones?
  134.                 THEN
  135.             THEN
  136.             1 --> n
  137.             litVal 1 >>  -> litVal
  138.     REPEAT
  139.     
  140. \ if we got here, it's OK as a mask.  n is one less than the bit number
  141. \  of the first 1.
  142.     n 1+  mEnd  true
  143. ;
  144.  
  145.  
  146. : TRY_CASCADE_SHIFT&MASK  { litVal \ mBegin mEnd -- b }
  147.  
  148.     false
  149.     
  150.     OK_for_cascade?  0EXIT
  151.     litVal canBeMask?  0EXIT
  152.  
  153.     -> mEnd  -> mBegin
  154.  
  155.     drop                                \ drop false flag
  156.     cascadeTest? if
  157.         ." cascading shift&mask on:" print: gprs
  158.         ." lit val we're ANDing: $" litval .h  cr cr
  159.     then
  160.  
  161.     get: ivar> maskBegin in GPRs  mBegin  max  -> mBegin
  162.     get: ivar> maskEnd     in GPRs  mEnd    min  -> mEnd
  163.  
  164.     addr: GPRs  ->: theOD
  165.     mBegin put: ivar> maskBegin in theOD
  166.     mEnd   put: ivar> maskEnd   in theOD
  167.  
  168.     [ cascadeTest? ] [if]
  169.         ." new theOD:"  print: theOD cr
  170.     [then]
  171.  
  172.     noRef >refType: opnd1            \ opnd1 is now gone - reg mustn't get free: from caller
  173.     true
  174. ;
  175.  
  176.  
  177. (*    check_complemented_operand looks for situations where we can generate
  178.     an andc or an orc by cascading an AND or OR with a preceding NOT.  We can
  179.     do this if they weren't immediate.  But it has to be the B operand which
  180.     gets complemented, so we switch them if necessary.
  181. *)
  182.  
  183. : CHECK_COMPLEMENTED_OPERAND  { \ complement? -- b }
  184.  
  185.     debug? if
  186.         ." check_complemented_operand called" cr
  187.     then
  188.     
  189.     false
  190.     false -> complement?
  191.  
  192. \ the A operand GPR is already selected
  193.  
  194.     get: ivar> opType in GPRs  otNOT  =
  195.     IF    true -> complement?
  196.         Bgpr: theOD  >Agpr: theOD        \ Bgpr will be set below
  197.     ELSE
  198.         Bgpr: theOD  select: GPRs
  199.         get: ivar> opType in GPRs  otNOT =
  200.         IF    true -> complement?
  201.             current: GPRs  -> antec#        \ it's different now
  202.         THEN
  203.     THEN
  204.  
  205.     antec# select: GPRs                        \ normal selection
  206.  
  207.     complement?  0EXIT                        \ out if no NOT
  208.     OK_for_cascade?  0EXIT                    \ or if NOT reg can't be deleted
  209.  
  210.     drop                                    \ drop the false flag
  211.     cascadeTest? if
  212.         ." cascading NOT and AND/OR - deleting " current: GPRs . cr
  213.         ." new OD in theOD:"  print: theOD cr
  214.     then
  215.  
  216.     Agpr: GPRs  >Bgpr: theOD            \ operand to be complemented
  217.     not: ivar> complB? in theOD
  218.  
  219.     Agpr: theOD  >gpr: opnd2  noRef >reftype: opnd1
  220.                                         \ only one reg to get free: from caller
  221.     true
  222. ;
  223.  
  224.  
  225. : TRY_CASCADE_AND  ( -- b )
  226.     Btype: theOD
  227.     CASE[    litRef    ]=>        get: ivar> opType in GPRs  otShift&mask =
  228.                             IF      Blit: theOD  try_cascade_shift&mask
  229.                             ELSE    false
  230.                             THEN
  231.  
  232.         [    gprRef    ]=>        check_complemented_operand
  233.         DEFAULT=>        drop  false
  234.     ]CASE
  235. ;
  236.  
  237.  
  238. : TRY_CASCADE_OR  ( -- b )
  239.     Btype: theOD  gprRef =  NIF  false  EXIT  THEN
  240.     check_complemented_operand
  241. ;
  242.  
  243.  
  244. (*    try_cascade_not checks for situations where we can generate a nand or a nor,
  245.     by cascading a NOT with a preceding AND, OR or XOR.  We can do this if
  246.     they weren't immediate.
  247. *)
  248.  
  249. : TRY_CASCADE_NOT  { \ prevOp -- b }
  250.  
  251.     false
  252.  
  253.     get: ivar> complB? in GPRs  ?EXIT        \ or if it's an andc or orc (can't complement
  254.                                             \ the result - we don't have "nandc" or "norc")
  255.     Agpr: theOD  select: GPRs
  256.     get: ivar> opType in GPRs  -> prevOp    \ grab preceding op
  257.     prevOp otAND =  prevOp otOR = or
  258.     prevOp otXOR = or  0EXIT                \ out if wrong sort
  259.     Atype: GPRs  gprRef =  0EXIT            \ out if either of its operands wasn't
  260.     Btype: GPRs  gprRef =  0EXIT            \  a GPR
  261.  
  262.     drop                                    \ OK, we'll do it.  Drop false flag
  263.     current: GPRs  -> antec#                \ may have changed
  264.  
  265.     [ cascadeTest? ] [if]
  266.         ." cascading NOT with earlier op:" print: gprs
  267.         ." theOD:"  print: theOD  cr cr
  268.     [then]
  269.  
  270.     addr: GPRs  ->: theOD                    \ copy op to theOD (which is where we need it)
  271.     not: ivar> complResult? in theOD        \ and set "complement result" flag
  272.  
  273.     noRef >refType: opnd1            \ opnd1 is now gone - reg mustn't get free: from caller
  274.     true
  275. ;
  276.     
  277.  
  278. : TRY_CASCADE_ADD  { op \ litVal Btype -- b }
  279.  
  280.     false
  281.  
  282.     Btype: theOD  litRef = 0EXIT            \ out if this op not literal
  283.     get: ivar> opType in GPRs otAdd = 0EXIT    \ or if prev op not add
  284.     OK_for_cascade?  0EXIT                    \ or if GPR op can't be deleted
  285.  
  286.     Blit: theOD  -> litVal
  287.     Btype: GPRs  -> Btype
  288.  
  289.     op otAdd =
  290.     IF                                    \ and if THIS op is add, the other add must
  291.         Btype litRef <> ?EXIT            \ be literal.
  292.  
  293.     ELSE    \ For fetch or store, we can add 2 regs, since indexed mode exists, but
  294.             \  the literal we're adding must be zero.  Note the only possibility
  295.             \  that can come up here is the antecedent op adding 2 regs, and this
  296.             \  op fetching/storing using the result reg and a literal zero.  The
  297.             \  antecedent op can't be a literal add of zero, since we never compile
  298.             \  those!
  299.         
  300.         Btype gprRef =
  301.         IF        litVal  ?EXIT
  302.         ELSE    Btype litRef <> ?EXIT
  303.         THEN
  304.     THEN
  305.                                             
  306.     get: ivar> special? in GPRs  ?EXIT        \ and only on a temp register - if on another
  307.                                             \ another reg, we need the value, so can't
  308.                                             \ delete the op.
  309.  
  310. \ Right, if we got here we'll do the cascade!
  311.  
  312.     drop                                    \ drop false flag
  313.  
  314.     cascadeTest? if
  315.         ." cascading adds on:" print: gprs
  316.         ." lit val we're adding: " litval .  cr
  317.         ." theOD:"  print: theOD  cr cr
  318.     then
  319.  
  320.     Btype: GPRs  GPRRef =
  321.     IF    Bgpr: GPRs  >Bgpr: theOD
  322.         noRef >refType: opnd2
  323.     ELSE
  324.         Blit: GPRs  ++> litVal                \ new literal value
  325.         litVal >Blit: theOD
  326.     THEN
  327.     Agpr: GPRs  >Agpr: theOD
  328.  
  329.     noRef >refType: opnd1            \ opnd1 is now gone - reg mustn't get free: from caller
  330.     true
  331. ;
  332.  
  333.  
  334. : TRY_CASCADE_FMADD  { op \ doit? subop add_fpr# ^ref_to_clear -- b }
  335.  
  336.     false -> doit?
  337.     multiply-add? NIF  false  EXIT  THEN    \ out if we're not doing it
  338.  
  339.     FPRs -> cas_regs  nilP -> ^ref_to_clear
  340.     op otFsub = if 1 else 0 then  -> subop
  341.  
  342. \ note: we need to check both the A and B operands of this op.  If either
  343. \  is a multiply, we might be able to generate a fmadd.
  344.  
  345.     Areg: theOD  dup -> antec#
  346.     select: FPRs
  347.     
  348.     cascadetest? if
  349.         ." try_cascade_fmadd here." cr
  350.         ." theOD:" print: theOD cr
  351.         ." Looking for 42 (otFmul) in A opnd FPR:" print: FPRs cr
  352.         dasm
  353.     then
  354.  
  355.     get: ivar> opType in FPRs otFmul =
  356.     IF  OK_for_cascade?
  357.         IF    get: ivar> special? in FPRs
  358.             NIF        true -> doit?
  359.                     Breg: theOD -> add_fpr#
  360.                     opnd1 -> ^ref_to_clear
  361.             THEN
  362.         THEN
  363.     THEN
  364.     
  365.     doit?
  366.     NIF        \ can't do it on the A operand - let's try B...
  367.         Bfpr: theOD  dup -> antec#
  368.         select: FPRs
  369.  
  370.         cascadetest? if
  371.             ." trying B opnd FPR:" print: FPRs cr
  372.         then
  373.  
  374.         get: ivar> opType in FPRs otFmul =
  375.         IF  OK_for_cascade?
  376.             IF    get: ivar> special? in FPRs
  377.                 NIF        \ yep, we can do it, but if it's mult-and-subtract,
  378.                         \ the operands are reversed.
  379.                     true -> doit?
  380.                     subop 2* -> subop
  381.                     Areg: theOD -> add_fpr#
  382.                     opnd2 -> ^ref_to_clear
  383.                 THEN
  384.             THEN
  385.         THEN
  386.     THEN
  387.     
  388.     doit? NIF  false  EXIT  THEN        \ out with false if we can't do it at all
  389.                                             
  390. \ Right, if we got here we'll do the cascade!
  391.  
  392.     cascadeTest? if
  393.         ." cascading floating mult and add on:" print: fprs
  394.     then
  395.  
  396.     Areg: FPRs    >Afpr: theOD
  397.     Breg: FPRs    >Bfpr: theOD    \ these operands get multiplied
  398.     add_fpr#    >Cfpr: theOD    \ this one gets added/subtracted
  399.  
  400.     otFmadd  put: ivar> opType in theOD
  401.     subop  put: ivar> subtype in theOD
  402.  
  403.     cascadetest? if
  404.         ." theOD as set up for fmadd:"  print: theOD  cr
  405.         ." setting this operand ref to noRef: "  print: [ ^ref_to_clear ]  cr
  406.     then
  407.     
  408.     noRef  ^ref_to_clear >refType: class_as> reference
  409.                 \ either opnd1 or opnd2 is now gone - reg mustn't get free: from caller
  410.     true
  411. ;
  412.  
  413.  
  414. : TRY_CASCADE  { \ op atype -- }
  415.  
  416.     cascade? 0EXIT            \ straight out if cascading turned off
  417.  
  418.     GPRs -> cas_regs        \ normal default
  419.  
  420.     cascadeTest? if
  421.         ." try_cascade called with theOD:" print: theOD cr
  422.     then
  423.     
  424.     get: ivar> opType in theOD  -> op        \  op is the new op we're compiling
  425.  
  426. \ first we won't cascade if we're not handling that reg type:
  427.  
  428.     Atype: theOD -> atype
  429.     atype gprRef =
  430.     IF    \ we set the A operand as the initial default for the reg we'll replace
  431.         \  if we cascade, but we won't check it yet since it might be a GPR-GPR 
  432.         \  op and we might end up cascading on the other operand.
  433.  
  434.         Agpr: theOD  dup -> antec#
  435.         select: GPRs
  436.     
  437.     ELSE
  438.         atype fprRef =  0EXIT        \ out if not gprRef or fprRef
  439.     THEN
  440.  
  441.     op  $ 2FF and        \ we want to include FP fetches with integer
  442.                         \  fetches, but not vector fetches!
  443.  
  444.     SELECT[    otAdd        ],
  445.           [ otFetch        ],
  446.           [    otStore        ]=>        op try_cascade_add
  447.  
  448.           [ otAnd        ]=>        try_cascade_and
  449.           [    otOr        ]=>        try_cascade_or
  450.           [    otNot        ]=>        try_cascade_not
  451.  
  452.           [    otFadd        ],
  453.           [    otFsub        ]=>        op try_cascade_fmadd
  454.                                           \ can change cas_regs to FPRs
  455.  
  456.             DEFAULT=>        drop false
  457.     ]SELECT
  458.     
  459.     cascadeTest? if
  460.         cr ." checking for cascade returns " dup . cr
  461.     then
  462.     
  463.     antec# select: cas_regs            \ antec# might have changed.  This should be
  464.                                     \  redundant, but you never know.
  465.  
  466.     cascadeTest? if
  467.         dup if    ." deleting: "  print: cas_regs cr
  468.                 ." new OD in theOD"  print: theOD cr
  469.             then
  470.     then
  471.     
  472.     IF    delete: cas_regs  THEN        \ if we cascaded, we delete the op we've made
  473.                                     \  redundant
  474. ;
  475.  
  476.  
  477. : CASCADE&MATCH?
  478.     try_cascade                    \ do the cascade if we can (and if we did,
  479.                                 \  theOD will have been appropriately modified
  480.     true match&allocate?
  481.     get: ivar> opType in theOD  -> operation
  482.     get: ivar> subtype in theOD -> suboperation
  483.  
  484.     cascadeTest? if
  485.         ." calling match&allocate? returns " dup . cr
  486.     then
  487. ;
  488.  
  489.  
  490. (*
  491. STRENGTH_REDUCE? is called if we have an op where one of the operands is
  492. literal.  We may be able to strength-reduce the op to something simpler.
  493. Currently we just do one: if the op is a multiply, and the literal is a
  494. power of 2, we convert it to a shift.
  495.  
  496. If we change the op, we then, as usual, check for a match with an op
  497. already in the regs.  If there's a match, we return true to show that
  498. there's nothing more to do.  Otherwise we return false.
  499. *)
  500.  
  501. : STRENGTH_REDUCE?  { \ litVal #bits n -- }
  502.     operation otMul <> IF  false  EXIT  THEN
  503.     Blit: theOD  -> litVal  0 -> #bits  -1 -> n
  504.     litVal 0<=  IF  false  EXIT  THEN
  505.     BEGIN    litVal
  506.     WHILE    litVal 1 and  ++> #bits
  507.             1 ++> n
  508.             litVal 1 >>  -> litVal
  509.     REPEAT
  510.     #bits 1 <>  IF  false  EXIT  THEN
  511.     
  512. \ yes, it's a power of 2 - n gives the power.
  513.  
  514.     otShift -> operation  0 -> subOperation
  515.     operation  put: ivar> opType in theOD
  516.     subOperation  put: ivar> subType in theOD
  517.     n >Blit: theOD
  518.     true match&allocate? IF  true  ELSE  false  THEN
  519. ;
  520.  
  521.  
  522. (*    RegLit_as_2_instrns? is called from CompRegLit if the literal is > 16 bits.
  523.     We see if it can be done as one or two instructions.
  524.     
  525.     For AND, OR and XOR, the andi, ori and xori instructions have shifted
  526.     forms, which means that we can do the op in 2 instructions, or 1 if the 
  527.     lower 16 bits are zero.  For ADD, if the literal value isn't too large,
  528.     we can do the op as two literal adds.
  529.     
  530.     If we can do one of these optimizations, we do it here and return true.
  531.     Otherwise we return false.
  532.     
  533.     On entry, we've already allocated a result reg and res1 is a reference
  534.     to it.   If we return true, we might have found a match, and in that case
  535.     we make sure res1 indicates the new result, and we free the old result reg.
  536.     
  537.     Special note: if we need 2 instructions, we have a choice:
  538.     A.  Generate the ops using 2 separate registers
  539.     B.  Reuse the one reg.
  540.     
  541.     Under A, we would call compile: GPRs twice, targetting a different GPR.
  542.     Under B, we could handle the whole thing in the compile: method
  543.     of OD, and only call it once from here.  There are pros and cons either 
  544.     way.  B is a bit simpler.  But for ADD, we'll often get
  545.     called for address generation where the target addresses have a lot
  546.     of locality, and we might be able to re-use intermediate values if we
  547.     use A and do it a bit cleverly.  But for the logicals, we're much
  548.     less likely to be able to reuse the intermediate values and so we'd
  549.     be using an extra register for nothing.  So we'll use A for ADD, and 
  550.     B for the logicals.
  551. *)
  552.  
  553.  
  554. : RegLit_as_2_instrns?  { litVal \ op n1 n2 dest_gpr# temp_gpr# -- b }
  555.  
  556.     false
  557.  
  558.     refType: opnd1  GPRref <> ?EXIT        \ can't do it if it's not a GPR->GPR op
  559.     refType: res1    GPRref <> ?EXIT
  560.  
  561.     operation -> op
  562.     reg: res1  -> dest_gpr#  0 -> temp_gpr#
  563.     
  564.     op otAND =
  565.     IF                        \ we can do it for AND iff the lo 16 bits are zero
  566.         litVal $ FFFF and  ?EXIT        \ out if they're not
  567.         true
  568.     ELSE
  569.         op otOR =  op otXOR =  or        \ we can always do it for OR and XOR
  570.     THEN
  571.     
  572.     IF        \ it's a logical op and we're to use plan B
  573.         0 -> n1  litVal -> n2
  574.     ELSE
  575.         op otAdd =  0EXIT                    \ out if op isn't add (no literal subtract)
  576.         litVal 2/ $ fffffc00 and -> n1        \ halve the literal & round down to
  577.                                             \  1024-byte boundary to increase
  578.                                             \  chance of a match later
  579.         n1 true 16bits? nip  0EXIT            \ if THAT won't fit in 16 bits, nogo
  580.         litVal n1 -  -> n2                    \ subtract that from orig literal
  581.         n2 true 16bits? nip  0EXIT            \ if that won't fit in 16 bits, nogo
  582.     THEN
  583.     
  584. \ if we got here, we can do it!
  585.     
  586.     drop true                                \ we'll be returning true
  587.  
  588.     n1 IF            \ we only do this for ADD (plan A)
  589.         n1 >Blit: theOD
  590.         
  591.         true match&allocate?
  592.         IF
  593.             current: GPRs  -> temp_gpr#
  594.         ELSE
  595.             getFreeReg: GPRs -> temp_gpr#
  596.             theOD ->: GPRs  compile: GPRs    \  compile the 1st op
  597.         THEN
  598.     
  599.         temp_gpr# >Agpr: theOD                \ result of 1st op is source for 2nd
  600.     THEN
  601.  
  602.     n2 >Blit: theOD
  603.     true match&allocate?
  604.     IF                                    \ match on 2nd op - res1 now points
  605.                                         \  to the new result.
  606.         dest_gpr# select: GPRs  free: GPRs
  607.     ELSE
  608.         dest_gpr# dup select: GPRs  >gpr: res1
  609.                                         \ res1 may have been changed by
  610.                                         \  the first match&allocate? call
  611.         theOD ->: GPRs  compile: GPRs
  612.     THEN
  613.     
  614. \ finally, whether anything matched or not, we have to free the
  615. \  intermediate reg, if there was one:
  616.  
  617.     temp_gpr# ?dup IF  select: GPRs  free: GPRs  THEN
  618. ;
  619.  
  620.  
  621. : compCRCR
  622.     debug? if
  623.         ." compCRCR called to compile a CR op.  theOD:" cr
  624.         print: theOD
  625.     then
  626.  
  627.     false 0 0 CR_result
  628.     theOD ->: CRs
  629.     compile: CRs
  630.     cmpLT  >condition: res1
  631.             \ it's fairly arbitrary, actually, but must agree with what we
  632.             \ put ihto rD.  Easiest is bit# 0, 1 is true, which means
  633.             \ "less than", so that's what we use.
  634. ;
  635.  
  636.  
  637. \ compRegReg factors out some common code from dyadic_arith and monadic_arith.
  638. \ theOD is set up with the new op we're about to compile.
  639.  
  640. : compRegReg    
  641.     true match&allocate?  ?EXIT        \ if it matches a result we already
  642.                                     \  have, we reuse it
  643.                                     
  644.     cascade&match?  ?EXIT            \ If we can cascade it with a preceding
  645.                                     \  op, we do it and we're done
  646.  
  647. \ now one or both operands might be in CRs, so we have to check.
  648.  
  649.     debug? if
  650.         ." compRegReg - match&allocate? and cascade&match?" cr
  651.         ." both returned false.  TheOD:" print: theOD cr
  652.     then
  653.  
  654.     Atype: theOD  fprRef =
  655.     IF
  656.         1 fresults
  657.     ELSE
  658.         Atype: theOD  gprRef =
  659.         IF    Btype: theOD  dup gprRef =  swap noRef =  or
  660.             NIF    Bref: theOD  get_to_gpr?
  661.                              IF        \ changed, so we update opnd2 so it gets
  662.                                      \  freed properly by the caller.  New ref is
  663.                                      \  always left in res1 by get_to_gpr?
  664.                                  res1 ->: opnd2
  665.                              THEN
  666.             THEN
  667.         ELSE
  668.             Btype: theOD  dup gprRef =  swap noRef =  or
  669.             IF    Aref: theOD  get_to_gpr? IF  res1 ->: opnd1  THEN
  670.             ELSE
  671.                 compCRCR  EXIT
  672.             THEN
  673.         THEN
  674.  
  675.     \ if we got here, both operands are in regs, even if they weren't
  676.     \  to start with.
  677.  
  678.         1 results
  679.     THEN
  680.  
  681.     theOD ->: theRegs
  682.     compile: theRegs
  683. ;
  684.  
  685.  
  686. (*    compRegLit is a lot more complicated.  It's called from several places where
  687.     we're doing a dyadic op where one operand is literal.  There are a lot of
  688.     possible optimizations.
  689.  
  690.     Unlike compRegReg, theOD is not set up yet, since we have to do some checks
  691.     first.
  692.     
  693.     We enter with the lit in opnd2, and the other operand is opnd1.
  694.     We leave res1 indicating the result.  Note that we allocate the result
  695.     reg fairly early, and set up res1, which means that if we later find
  696.     a match or change the result reg for some reason, we need to free: res1.
  697. *)
  698.  
  699. objPtr    OP_resultReg  class_is OD
  700.  
  701.  
  702. : compRegLit  { \ reg# litVal sgnd? comp? -- }
  703.  
  704.     lit: opnd2  -> litVal
  705.  
  706.     clear: theOD  operation  put: ivar> opType in theOD
  707.     subOperation  put: ivar> subType in theOD
  708.  
  709.     operation  dup signed? -> sgnd?
  710.     dup otCMP =  swap otUCMP = or  -> comp?
  711.  
  712.     debug? if
  713.         cr
  714.         ." compRegLit - " cr
  715.         ." opnd1 " print: opnd1
  716.         ."  litVal " litVal . ."  sgnd? " sgnd? .  ."  comp? " comp? . cr
  717.         ." operation " operation .h cr
  718.         printall: cstk
  719.     then
  720.  
  721. \ First, there's no literal divide or multiply high instruction - so if
  722. \  we have this, we need to load the literal into a reg and change to
  723. \  a reg-reg op.
  724.  
  725.     operation otDiv =
  726.     operation otUDiv =  or
  727.     operation otMulh =  or
  728.     IF
  729.         theOD copyOD: tmpOD
  730.         litVal false  lit>gpr
  731.         tmpOD copyOD: theOD
  732.         opnd1  ->: ivar> A_opnd in theOD
  733.         res1   ->: ivar> B_opnd in theOD    \ this was set by lit>gpr
  734.         compRegReg   EXIT
  735.     THEN
  736.  
  737. \ Next, there's no literal subtract instruction - so in this case
  738. \  we need to negate the literal value and change the op to add.
  739.  
  740.     operation otSub =
  741.     IF    neg> litVal  otAdd -> operation  THEN
  742.  
  743.     operation  put: ivar> opType in theOD        \ may not have been set up, and
  744.                                                 \  in any case may have changed
  745.     reg: opnd1  -> reg#            \ may be a gpr or cr reference
  746.     litVal  >BLit: theOD
  747.  
  748. \ Now, we can get rid of some trivial cases.  Object binding and inline
  749. \ definitions can produce things like 0 +  or  -1 AND  for which we don't
  750. \ have to generate any code.  For these, we just set res1 and get out.
  751. \ The res1 result is either a literal -1 or 0, or it's a copy of opnd1.
  752. \ In the cases where we transfer opnd1 to res1, we clear opnd1 so that 
  753. \ its register doesn't get freed (we're still using it, of course).
  754.  
  755.     operation otAnd =
  756.     IF    litval
  757.         NIF    debug? if  ." anding zero - replacing with zero" cr  then
  758.             0 >lit: res1  free: opnd1  delete: opnd1  EXIT
  759.         ELSE
  760.             litval -1 =
  761.             IF    debug? if  ." anding -1 - moving opnd1 to res1" cr  then
  762.                 opnd1 ->: res1  clear: opnd1  EXIT
  763.             THEN
  764.         THEN
  765.     THEN
  766.  
  767.     operation otOr =
  768.     IF    litval
  769.         NIF    debug? if  ." oring 0 - moving opnd1 to res1" cr  then
  770.             opnd1 ->: res1  clear: opnd1  EXIT
  771.         ELSE
  772.             litval -1 =
  773.             IF    debug? if  ." oring -1 - replacing with -1" cr  then
  774.                 -1 >lit: res1  free: opnd1  delete: opnd1  EXIT
  775.             THEN
  776.         THEN
  777.     THEN
  778.  
  779.     operation otAdd =
  780.     IF    debug? if  ." adding 0 - moving opnd1 to res1" cr  then
  781.         litval NIF  opnd1 ->: res1  clear: opnd1  EXIT  THEN
  782.     THEN
  783.  
  784. \ Next, if the operation is And, and the literal could be a mask, we
  785. \  can replace the And with a rotate left (by zero) and mask.  This
  786. \  doesn't involve accessing the CR, unlike andi., so it's recommended
  787. \  we do it.
  788.  
  789.     refType: opnd1
  790.  
  791.     SELECT[    gprRef    ]=>
  792.                 reg#  >Agpr: theOD
  793.                 true match&allocate? ?EXIT    \ if it already exists, we're done.
  794.  
  795.                 cascade&match?         ?EXIT    \ if we cascaded and it already exists
  796.                 Blit: theOD -> litVal        \ may have changed
  797.                 Agpr: theOD >gpr: opnd1        \ likewise
  798.  
  799.                 strength_reduce?  ?EXIT        \ if we strength-reduced & it alr exists
  800.     
  801.           [    CRref    ]=>            \ CR - lit operation - normally we'll have to
  802.                                   \  get the CR to a GPR first.  The only exceptions
  803.                                   \  are the degenerate cases where the op is a logical
  804.                                   \  or comparison, and the lit is -1 or 0.  At the
  805.                                   \  moment we won't bother with these optimizations
  806.                                   \  (which would probably be pretty rare anyway).
  807.                   reg# >Acr: theOD
  808.                 true match&allocate?  ?EXIT        \ if it already exists, we're done.
  809.  
  810.                   opnd1 cr>gpr  res1 ->: opnd1    \ cr>gpr frees the CR
  811.  
  812.                 debug? if
  813.                     ." opnd1 is CR - converted to: " print: opnd1 cr
  814.                 then
  815.                 
  816.                 gpr: opnd1  dup -> reg#  >Agpr: theOD
  817.  
  818.             DEFAULT=>  to_be_written  drop
  819.  
  820.     ]SELECT
  821.  
  822.     false -> check_OP_stores?        \ we must have this checking turned
  823.                                     \  off, since large_obj_array elements
  824.                                     \  don't have class pointers
  825.  
  826.     comp?
  827.     IF    false 0 0 CR_result        \ for comparisons, dest is a CR.  Get a CR result reg
  828.         addr: CRs  -> OP_resultReg
  829.         litVal sgnd? 16bits? nip
  830.         IF    theOD ->: CRs
  831.             compile: CRs  EXIT
  832.         THEN
  833.     ELSE
  834.         1 results        \ get a GPR result reg
  835.         addr: GPRs  -> OP_resultReg
  836.  
  837.         debug? if
  838.             ." result reg will be "  print: gprs  cr
  839.         then
  840.  
  841.     \ now if the op is And, and the literal could be a mask
  842.     \  for a rotate left and mask instruction, it's better if we
  843.     \  use that (with a zero rotate), since it doesn't store to 
  844.     \  the condition reg (unlike andi.).
  845.     
  846.         operation otAnd =
  847.         IF
  848.             litVal canBeMask?
  849.             IF    theOD ->: GPRs
  850.                 otShift&mask    put: ivar> opType        in GPRs
  851.                                 put: ivar> maskEnd        in GPRs
  852.                                 put: ivar> maskBegin    in GPRs
  853.                             0    >lit: ivar> B_opnd        in GPRs        \ rotate by 0
  854.                 compile: GPRs  EXIT
  855.             THEN
  856.         THEN
  857.  
  858.         litVal sgnd? 16bits? nip
  859.         IF    theOD ->: GPRs
  860.             compile: GPRs
  861.             debug? if
  862.                 ." just compiled this reg:" print: GPRs
  863.                 printall: cstk
  864.             then
  865.             EXIT
  866.         THEN
  867.     THEN
  868.  
  869. (*    If we got to here, the literal was >16 bits.  We may have to load
  870.     the long literal into a register, then do a 2-reg op.  This will
  871.     take a total of 3 instructions.  But there are some other things
  872.     we can try - if the operation is add, and, or or xor, we may be 
  873.     able to do the op in 1 or 2 instructions.  We handle this
  874.     in regLit_as_2_instrns?.
  875.     
  876.     Note that at this point we've allocated the result reg, and it's
  877.     selected in GPRs.  If we match on a value in another reg, we'll
  878.     have to free the result reg we have now.
  879. *)
  880.  
  881. (*    operation otAnd =
  882.     IF
  883.         litVal canBeMask?
  884.         IF    theOD ->: GPRs
  885.             otShift&mask    put: ivar> opType        in GPRs
  886.                             put: ivar> maskEnd        in GPRs
  887.                             put: ivar> maskBegin    in GPRs
  888.                         0    >lit: ivar> B_opnd        in GPRs        \ rotate by 0
  889.             compile: GPRs  EXIT
  890.         THEN
  891.     THEN
  892. *)
  893.     litVal regLit_as_2_instrns?  ?EXIT        \ if we did it, we're done
  894.  
  895. \ Right, we have to compile a load of the long literal into a reg, then use the
  896. \  reg.  This case then becomes like a normal 2-reg op (see below)
  897.  
  898.     litVal setLit: theOD
  899.  
  900.     theOD  true  match?
  901.     IF    drop
  902.         debug? if
  903.             ." long lit matched on:" print: GPRs  .s
  904.         then
  905.         
  906.         allocate: GPRs
  907.         current: GPRs  dup -> reg#  >GPR: opnd2
  908.     ELSE
  909.         getFreeReg: GPRs                \ get reg we're going to load into
  910.         theOD  ->: GPRs
  911.         dup -> reg#  >GPR: opnd2
  912.         compile: GPRs                    \ compile load of the long lit
  913.     THEN
  914.  
  915.     debug? if
  916.         ." long lit was loaded - res1 before compiling op:" print: res1 cr
  917.         ." result reg:" print: OP_resultReg cr  .s
  918.     then
  919.  
  920.     gpr: opnd1    >Agpr: OP_resultReg
  921.     reg#        >Bgpr: OP_resultReg
  922.     operation put: ivar> opType in OP_resultReg  compile: OP_resultReg
  923.  
  924.     gpr: opnd2  select: GPRs  free: GPRs
  925.                                 \ free the temp reg we used for the lit
  926. ;
  927.  
  928.  
  929. \ nonCom_litReg is called from dyadic_arith when the first operand is literal
  930. \  and the second is in a register, and the op is non-commutative so we can't
  931. \  just swap the operands.  We load the literal into a reg and do a reg-reg op.
  932. \  (The code is similar to that near the start of compRegLit above, when we
  933. \  handle an operation that doesn't have a literal instruction.)
  934.  
  935. : NONCOM_LITREG  { \ litVal -- }
  936.     lit: opnd1  -> litVal
  937.     theOD copyOD: tmpOD
  938.     litVal false  lit>gpr
  939.     tmpOD copyOD: theOD
  940.     res1   ->: ivar> A_opnd in theOD    \ this was set by lit>gpr
  941.     opnd2  ->: ivar> B_opnd in theOD
  942.     compRegReg
  943. ;
  944.  
  945.  
  946. : COMMUTATIVE?  ( op -- b )
  947.     CASE[    otSub            ],
  948.         [    otDiv            ],
  949.         [    otUDiv            ],
  950.         [    otShift            ],
  951.         [    otShift&mask    ],
  952.         [    otTrap            ]=>        false
  953.         
  954.         DEFAULT=>                    drop true
  955.     ]CASE
  956. ;
  957.  
  958.  
  959. : FP_DYADIC_ARITH
  960.  
  961.     FPRs -> theRegs
  962.     2 foperands
  963.  
  964.     opnd1  ->: ivar> A_opnd in theOD
  965.     opnd2  ->: ivar> B_opnd in theOD
  966.     compRegReg
  967.     free: opnd1  free: opnd2
  968.     res1 fpush
  969.     GPRs -> theRegs        \ normal default - might be best to put it back
  970.  
  971.     debug? if
  972.         ." fp_dyadic_arith finished:" cr
  973.         ." cstk:  " printall: cstk cr
  974.         ." cstk2: " printall: cstk2 cr
  975.         ." fcstk: " printall: fcstk cr
  976.         ." fcstk2:" printall: fcstk2 cr
  977.         dasm
  978.     then
  979. ;
  980.  
  981. : FP_MONADIC_ARITH
  982.  
  983.     FPRs -> theRegs
  984.     1 foperands
  985.  
  986.     opnd1  ->: ivar> A_opnd in theOD
  987.  
  988.     compRegReg
  989.     free: opnd1
  990.     res1 fpush
  991.     GPRs -> theRegs        \ normal default - might be best to put it back
  992.  
  993.     debug? if
  994.         ." fp_monadic_arith finished:" cr
  995.         ." cstk:  " printall: cstk cr
  996.         ." cstk2: " printall: cstk2 cr
  997.         ." fcstk: " printall: fcstk cr
  998.         ." fcstk2:" printall: fcstk2 cr
  999.         dasm
  1000.     then
  1001. ;
  1002.  
  1003.  
  1004. : DYADIC_ARITH
  1005.     debug? if
  1006.         cr
  1007.         ." dyadic_arith -" cr
  1008.         ." operation " operation .h  ."   subOperation " subOperation .h cr
  1009.         printall: cstk
  1010.     then
  1011.  
  1012.     GPRs -> theRegs
  1013.     clear: instrn  clear: theOD
  1014.     operation  put: ivar> opType in theOD
  1015.     subOperation  put: ivar> subType in theOD
  1016.  
  1017.     operation otFPstart >= IF  FP_dyadic_arith  EXIT  THEN
  1018.  
  1019.     2 operands
  1020.     refType: opnd1  dup litRef > IF 221 die THEN        \ "Impossible operand!"
  1021.                     litRef =  negate 2*
  1022.     refType: opnd2  dup litRef > IF 221 die THEN
  1023.                     litRef =  negate or
  1024.     
  1025.     SELECT[    0    ]=>            \ Both operands are regs
  1026.                     opnd1  ->: ivar> A_opnd in theOD
  1027.                     opnd2  ->: ivar> B_opnd in theOD
  1028.                     compRegReg
  1029.                     
  1030.           [    1    ]=>            \ 1st op reg, 2nd lit
  1031.                       compRegLit
  1032.           
  1033.           [    2    ]=>            \ 1st op lit, 2nd reg.  If the op is commutative, we can
  1034.                               \  just swap the operands and call compRegLit.  If it's
  1035.                               \  subtract, we can change it to subfic and do the same
  1036.                               \  thing.  Otherwise we have to do a bit more juggling so
  1037.                               \  we call nonCom_litReg to handle it.
  1038.                               
  1039.                       operation otSub =
  1040.                       IF        otSubfc -> operation  true
  1041.                       ELSE    operation  commutative?
  1042.                       THEN
  1043.                       
  1044.                       IF
  1045.                           opnd1 ->: res3  opnd2 ->: opnd1  res3 ->: opnd2
  1046.                           compRegLit
  1047.                       ELSE    
  1048.                           nonCom_litReg
  1049.                       THEN
  1050.           
  1051.           [    3    ]=>            \ Both lit - execute the op right now!
  1052.                       lit: opnd1  lit: opnd2
  1053.                       operation subOperation getImmediateOp  execute
  1054.                       >lit: res1
  1055.  
  1056.           DEFAULT=>  drop
  1057.     ]SELECT
  1058.     free: opnd1  free: opnd2
  1059.     res1 push
  1060.     true -> check_OP_stores?    \ may have been turned off
  1061. ;
  1062.  
  1063.  
  1064. : MONADIC_ARITH
  1065.     debug? if
  1066.         cr
  1067.         ." monadic_arith -" cr
  1068.         ." operation " operation .h  ."   subOperation " subOperation .h cr
  1069.         printall: cstk
  1070.     then
  1071.  
  1072.     GPRs -> theRegs
  1073.  
  1074.     clear: instrn  clear: theOD
  1075.     operation  put: ivar> opType in theOD
  1076.     subOperation  put: ivar> subType in theOD
  1077.  
  1078.     operation otFPstart >= IF  FP_monadic_arith  EXIT  THEN
  1079.  
  1080.     1 operands
  1081.     refType: opnd1  litRef > IF 221 die THEN        \ "Impossible operand!"
  1082.  
  1083.     opnd1  ->: ivar> A_opnd in theOD
  1084.     
  1085.     true match&allocate?  ?EXIT        \ if it matches a result we already
  1086.                                     \  have, we reuse it
  1087.                                     
  1088.     cascade&match?  ?EXIT            \ If we can cascade it with a preceding
  1089.                                     \  op, we do it and we're done
  1090.     refType: opnd1
  1091.     SELECT[    gprRef    ]=>        gpr: opnd1  >Agpr: theOD
  1092.                             compRegReg
  1093.  
  1094.           [    fprRef    ]=>            to_be_written
  1095.  
  1096.           [    CRref    ]=>        operation otNOT =
  1097.                               IF        \ we can use a CR op
  1098.                                   compCRCR        \ this does everything
  1099.                                 res1 push   EXIT
  1100.                               ELSE
  1101.                                   opnd1 get_to_gpr? drop
  1102.                               THEN
  1103.                               gpr: opnd1  >Agpr: theOD
  1104.                               compRegReg
  1105.  
  1106.           [    litRef    ]=>            \ execute the op right now!
  1107.                                 lit: opnd1
  1108.                               operation subOperation getImmediateOp  execute
  1109.                               >lit: res1
  1110.  
  1111.     DEFAULT=>
  1112.     ]SELECT
  1113.  
  1114.     free: opnd1
  1115.     res1 push
  1116.     true -> check_OP_stores?    \ may have been turned off
  1117. ;
  1118.  
  1119.  
  1120. : special_arith?    \ handles things like subfze.  We only include the ones we 
  1121.                     \  actually want.  Also, as we're only generating them 
  1122.                     \  internally, we can kludge a bit, and assume the
  1123.                     \  operands are of the right sort.  We'll just get an error 
  1124.                     \  if they're not, which won't affect users.
  1125.     operation
  1126. \    SELECT[    otAddic        ],
  1127. \          [    otSubfic    ]=>        1 operands
  1128. \                                litref >reftype: opnd1        \ shd always be literal
  1129. \                                opnd1 push  dyadic_arith  true
  1130.     SELECT[    otAddze        ],
  1131.           [    otAddme        ],
  1132.           [    otSubfze    ],
  1133.           [    otSubfme    ]=>        0 >gpr: res1  res1 push
  1134.                                   dyadic_arith  true  
  1135.  
  1136.     \      [    otAddc        ],
  1137.     \      [    otAdde        ],
  1138.     \      [    otSubfc        ],
  1139.     \      [    otSubfe        ]=>
  1140.  
  1141.         DEFAULT=>  drop  false
  1142.     ]SELECT
  1143. ;
  1144.  
  1145.  
  1146. : DO_ARITH_OP
  1147.     special_arith?  ?EXIT        \ out if it was special, and we handled it
  1148.     operation monadic? nip
  1149.     IF  monadic_arith  ELSE  dyadic_arith  THEN
  1150. ;
  1151.  
  1152.  
  1153. : GENERATE_CR_RESULT  { \ reg# cr# wantit? xx -- }
  1154.  
  1155.     0 -> cr#  false -> wantit?
  1156.  
  1157.     Atype: theOD  FPRref =  IF  1 -> cr#  THEN
  1158.     
  1159.     reg: ivar> A_opnd in theOD  dup -> reg#  select: theRegs
  1160.     
  1161. (*    We first see if we can avoid a cmp by modifying the antecedent op to set
  1162.     CR0 (or CR1 if it's FP).  This situation is a bit like cascading, but a 
  1163.     bit different too.  The main difference is that if we modify the 
  1164.     antecedent to set CR0, we haven't actually changed its result, so its 
  1165.     refcnt and other uses of that reg don't matter.  But we do still have
  1166.     to check for a basic block boundary, since we can't rely on CR0 still
  1167.     being valid over such a boundary - in fact, it generally won't be.
  1168. *)
  1169.     get: ivar> opCDP in theRegs  basic_block_start  u>=
  1170.                             \ there's no BB boundary - if there is, we
  1171.                             \  can't optimize to use CR0/1, regardless
  1172.     IF
  1173.         get: ivar> instrnType in theRegs
  1174.         SELECT[    arithType        ],
  1175.               [ logicalType        ]=>                \ OK unless literal
  1176.                                         Btype: theRegs  litRef <>
  1177.               [    shiftType        ]=>                \ always OK
  1178.                                           true
  1179.  
  1180.         DEFAULT=>    drop false
  1181.         ]SELECT
  1182.     
  1183.         -> wantit?
  1184.     
  1185.     \ but there's one special exception - literal AND ( andi. ) always sets CR0
  1186.     \  no matter what!  Note, if we're in the FPRs, the op won't ever be otAnd,
  1187.     \  but the following test is still valid so we don't need to check for this case.
  1188.  
  1189.         wantit? 
  1190.         NIF
  1191.             get: ivar> opType in theRegs otAnd =
  1192.             Btype: theRegs  litRef =
  1193.             and  -> wantit?
  1194.         THEN
  1195.     THEN
  1196.  
  1197.     wantit?  cr#
  1198.     get: ivar> opCDP in theRegs
  1199.     CR_result
  1200.  
  1201.     current: CRs cr# =  wantit? and
  1202.     IF                \ we can set the CR field by recompiling the op
  1203.         setCR: theRegs
  1204.         recompile: theRegs
  1205.         get: ivar> opCDP in theRegs  mark_use: theRegs
  1206.                             \ that was an implicit reference to that reg
  1207.  
  1208.     ELSE            \ we have to compile a cmp
  1209.         theOD ->: CRs
  1210.         compile: CRs
  1211.     THEN
  1212. ;
  1213.  
  1214.  
  1215. (*    modify_condition is called when a monadic condition reference references
  1216.     another condition reference (e.g. ... < 0= - doesn't look very logical,
  1217.     but inline code could cause this to happen).  The initial ref is in opnd1,
  1218.     and the conditional op is in subOperation.  The result ref goes into res1.
  1219.     The situation we're modelling is that the first op has left a flag on the
  1220.     data stack, which of course is -1 or 0.  So the possible transformations
  1221.     are:
  1222.         1st op        monadic op        result
  1223.         -1            0<>                -1
  1224.                     0=                0
  1225.                     0>=                0
  1226.                     0<                -1
  1227.                     0<=                -1
  1228.                     0>                0
  1229.         
  1230.         0            0<>                0
  1231.                     0=                -1
  1232.                     0>=                -1
  1233.                     0<                0
  1234.                     0<=                -1
  1235.                     0>                0
  1236.  
  1237.     That is, the condition is simply inverted for all ops except 0<= and 0>,
  1238.     which are left unchanged.
  1239. *)
  1240.  
  1241.  
  1242. : MODIFY_CONDITION
  1243.     addr: opnd1  ->: res1
  1244.     suboperation  cmpZLE =  suboperation  cmpZGT = or  ?EXIT
  1245.     not: ivar> 1_is_true? in res1
  1246. ;
  1247.  
  1248.  
  1249. : DYADIC_COMPARISON        \ ( unsigned? -- )
  1250.     \ Note: operation not set up yet.  The comparison code is in
  1251.     \  subOperation.
  1252.  
  1253.     debug? if
  1254.         ." dyadic_comparison -" cr
  1255.         ." subOperation " subOperation .h cr
  1256.     then
  1257.  
  1258.     GPRs -> theRegs
  1259.  
  1260.     clear: instrn  clear: theOD
  1261.     IF otUCMP ELSE otCMP THEN  dup -> operation
  1262.                     put: ivar> opType in theOD
  1263.     subOperation    put: ivar> subtype in theOD
  1264.  
  1265.     2 operands
  1266.     refType: opnd1  litRef =  negate 2*
  1267.     refType: opnd2  litRef =  negate or
  1268.     
  1269.     SELECT[    0    ]=>            \ Both operands are regs (GPR or CR)
  1270.  
  1271.                     opnd1 get_to_gpr? drop
  1272.                     opnd2 get_to_gpr? drop
  1273.  
  1274.                     gpr: opnd1  >Agpr: theOD
  1275.                     gpr: opnd2  >Bgpr: theOD
  1276.                     theOD  true  match?: CRs
  1277.                     IF    allocate: CRs
  1278.                         current: CRs  >CR: res1  subOperation >condition: res1
  1279.                         res1 ->: ivar> myRef in CRs
  1280.                     ELSE
  1281.                         false 0 0 CR_result
  1282.                         theOD ->: CRs
  1283.                         compile: CRs
  1284.                     THEN
  1285.                      
  1286.           [    1    ]=>            \ 1st op reg, 2nd lit
  1287.                       compRegLit
  1288.           
  1289.           [    2    ]=>            \ 1st op lit, 2nd reg
  1290.                       reverse_comparison
  1291.                       opnd1 ->: res3  opnd2 ->: opnd1  res3 ->: opnd2
  1292.                       compRegLit
  1293.           
  1294.           [    3    ]=>            \ Both lit
  1295.                       lit: opnd1  lit: opnd2
  1296.                       operation subOperation getImmediateOp  execute
  1297.                       >lit: res1
  1298.  
  1299.           DEFAULT=>  drop
  1300.     ]SELECT
  1301.     
  1302.     free: opnd1  free: opnd2
  1303.     res1 push
  1304.     true -> check_OP_stores?    \ may have been turned off
  1305. ;
  1306.  
  1307.  
  1308. : MONADIC_COMPARISON    \  ( unsigned? -- )
  1309.     \ Note: operation not set up yet.  The comparison code is in
  1310.     \  subOperation.
  1311.  
  1312.     GPRs -> theRegs
  1313.  
  1314.     clear: instrn  clear: theOD
  1315.     IF otUCMP ELSE otCMP THEN  dup -> operation
  1316.                     put: ivar> opType in theOD
  1317.     subOperation    put: ivar> subtype in theOD
  1318.     0  >Blit: theOD        \ second operand is literal zero
  1319.     1 operands
  1320.     refType: opnd1
  1321.  
  1322.     SELECT[    gprRef    ]=>            \ operand is in a gpr
  1323.                     gpr: opnd1  >Agpr: theOD
  1324.                     true match&allocate?
  1325.                     NIF
  1326.                         generate_CR_result
  1327.                     THEN
  1328.  
  1329.           [    crRef    ]=>        \ operand is in a cr so the test has been done - we
  1330.                               \  can just modify the existing reference
  1331.                               \  appropriately
  1332.                       modify_condition  res1 push  EXIT
  1333.  
  1334.           [    litRef    ]=>        \ execute the op right now!
  1335.                         lit: opnd1
  1336.                     operation subOperation getImmediateOp  execute
  1337.                       >lit: res1
  1338.  
  1339.           DEFAULT=>  drop
  1340.     ]SELECT
  1341.     
  1342.     free: opnd1
  1343.     res1 push
  1344. ;
  1345.  
  1346.  
  1347. : FP_DYADIC_COMPARISON
  1348.     debug? if
  1349.         ." fp_dyadic_comparison -" cr
  1350.         ." subOperation " subOperation .h cr
  1351.     then
  1352.     
  1353.     FPRs -> theRegs
  1354.  
  1355.     clear: instrn  clear: theOD
  1356.     otFPcmp  dup -> operation
  1357.                     put: ivar> opType in theOD
  1358.     subOperation    put: ivar> subtype in theOD
  1359.  
  1360.     2 foperands
  1361.  
  1362.     opnd1  ->: ivar> A_opnd in theOD
  1363.     opnd2  ->: ivar> B_opnd in theOD
  1364.  
  1365.     theOD  true  match?: CRs
  1366.     IF    allocate: CRs
  1367.         current: CRs  >CR: res1  subOperation >condition: res1
  1368.         res1 ->: ivar> myRef in CRs
  1369.     ELSE
  1370.         false 0 0 CR_result
  1371.         theOD ->: CRs
  1372.         compile: CRs
  1373.     THEN
  1374.  
  1375.     free: opnd1  free: opnd2
  1376.     res1 push
  1377.     true -> check_OP_stores?    \ may have been turned off
  1378.     GPRs -> theRegs                \ normal default - might be best to put it back
  1379.  
  1380.     debug? if
  1381.         ." fp_dyadic_comparison finished:" cr
  1382.         ." cstk:  " printall: cstk cr
  1383.         ." cstk2: " printall: cstk2 cr
  1384.         ." fcstk: " printall: fcstk cr
  1385.         ." fcstk2:" printall: fcstk2 cr
  1386.         dasm
  1387.     then
  1388. ;
  1389.  
  1390. : FP_MONADIC_COMPARISON
  1391.     debug? if
  1392.         ." fp_monadic_comparison -" cr
  1393.         ." subOperation " subOperation .h cr
  1394.     then
  1395.     
  1396.     FPRs -> theRegs
  1397.  
  1398.     clear: instrn  clear: theOD
  1399.     otFPcmp  dup -> operation
  1400.                     put: ivar> opType in theOD
  1401.     subOperation    put: ivar> subtype in theOD
  1402.  
  1403.     1 foperands
  1404.  
  1405.     fpr: opnd1  >Afpr: theOD
  1406.     true match&allocate?
  1407.     NIF
  1408.         generate_CR_result
  1409.     THEN
  1410.     free: opnd1
  1411.     res1 push
  1412.     
  1413.     true -> check_OP_stores?    \ may have been turned off
  1414.     GPRs -> theRegs                \ normal default - might be best to put it back
  1415.  
  1416.     debug? if
  1417.         ." fp_monadic_comparison finished:" cr
  1418.         ." cstk:  " printall: cstk cr
  1419.         ." cstk2: " printall: cstk2 cr
  1420.         ." fcstk: " printall: fcstk cr
  1421.         ." fcstk2:" printall: fcstk2 cr
  1422.         dasm
  1423.     then
  1424. ;
  1425.  
  1426. : SETUP_CONDITIONAL_BRANCH  { ^ref invert? \ whichBit -- }
  1427.     false -> check_OP_stores?    \ may be a reference_list instead of a reference,
  1428.     ^ref -> aRef                \  so we bypass the type check.
  1429.     true -> check_OP_stores?
  1430.     debug? if
  1431.         ." setup_conditional_branch called with "  print: aRef cr
  1432.     then
  1433.  
  1434.     16 >primOp: branch_instrn
  1435.  
  1436.     refType: aRef  CRref <>
  1437.     IF  ." ref passed to setup_conditional_branch not a CR ref" cr
  1438.         print: aRef  1 die
  1439.     THEN
  1440.  
  1441.     reg: aRef  4*  bit#: aRef or  -> whichBit
  1442.     true put: ivar> use_cond? in branch_instrn
  1443.     1_is_true?: aRef  invert? xor  put: ivar> branchOn1? in branch_instrn
  1444.     whichBit  >RA: branch_instrn
  1445. ;
  1446.  
  1447. \ : SETUP_UNCONDITIONAL_BRANCH
  1448. \    18 >primOp: uncond_branch_instrn
  1449. \    0  >lit: branch_instrn                \ for now - will be patched
  1450. \ ;
  1451.     
  1452. : COMPILE_UNCONDITIONAL_BRANCH
  1453. \    setup_unconditional_branch
  1454. \    compile: uncond_branch_instrn
  1455.     $ BF080000  code,
  1456. ;
  1457.  
  1458.  
  1459.  
  1460. (* COMBINE_BRANCHES is called when we have a conditional branch over a
  1461.    single unconditional branch or EXIT.  We can usually combine these
  1462.    into a single conditional branch.
  1463.    Note that a normal uncond. branch has the temp opcode BF08, an ELSE-
  1464.    branch has BF09, and an EXIT has BF02.  We don't use temp opcodes for
  1465.    conditional branches, so if we combine the branches and it's not an
  1466.    EXIT, we just emit a regular conditional branch.
  1467.  
  1468.    branchCDP is the addr of the 1st of the 2 branches.
  1469.    
  1470.    Note we only call this routine if the first branch is conditional.
  1471.    An ELSE branch can occur over another branch, but we handle that
  1472.    below in RESOLVE_ELSE.
  1473.    
  1474.    This also means we can assume here that branch_instrn is set up for
  1475.    the conditional branch, so we can easily invert the condition and
  1476.    recompile it.
  1477. *)
  1478.  
  1479. : COMBINE_BRANCHES  { branchCDP \ svCDP offs len -- }
  1480.     debug? if
  1481.         ." combine_branches called - there's a branch over "
  1482.     then
  1483.     CDP -> svCDP
  1484.     branchCDP 4+ w@
  1485.     CASE[    $ BF02    ]=>        \ it's an EXIT - marked by temp opcode BF02
  1486.                             \  until resolved at the end of the definition.  We
  1487.                             \  convert it to a conditional exit (opcode BF03).
  1488.                 debug? if
  1489.                     ." an EXIT" cr
  1490.                 then
  1491.                 branchCDP -> CDP
  1492.                 invert: branch_instrn  compile: branch_instrn
  1493.                 branchCDP @  16 >>  $ BF030000 or  branchCDP !  EXIT
  1494.  
  1495.         [ $ BF08 ], [ $ BF09 ]=>    \ uncond branch / ELSE-branch
  1496.                 debug? if
  1497.                     ." an uncond. branch" cr
  1498.                 then
  1499.                 branchCDP 2+ w@x  -> offs
  1500.                 offs 0EXIT            \ 2nd branch not resolved yet - can't combine
  1501.                 
  1502.         DEFAULT=>
  1503.     ]CASE
  1504.  
  1505.     \ We'll combine.  We need to retain the offset since we're going to
  1506.     \  move any following code to fill the gap, so the offset will stay
  1507.     \  the same.
  1508.  
  1509.     branchCDP -> CDP
  1510.     invert: branch_instrn  compile: branch_instrn
  1511. \    branchCDP  branchCDP 4+ offs +  resolve_branch
  1512.     offs  branchCDP 2+  w!
  1513.  
  1514. \ now if there's any code between that collapsed branch and the present
  1515. \  CDP position, we have to move it back by 4 bytes.  
  1516. \  ASSERT: there won't be a resolved branch pointing to anywhere in
  1517. \  the middle of the code we're moving!
  1518.  
  1519.     svCDP branchCDP 4+ -  -> len
  1520.     len 0>
  1521.     IF    branchCDP 8 + dup 4-  len  move        \ areas overlap, so don't use
  1522.                                             \  aligned_move
  1523.         svCDP 4-
  1524.     ELSE
  1525.         svCDP
  1526.     THEN  -> CDP
  1527. ;
  1528.  
  1529.  
  1530. : RESOLVE_ELSE  { branchCDP destCDP \ offs condCDP len wipeBoth? -- }
  1531.     destCDP branchCDP -  -> offs
  1532.     offs 4 =
  1533.     IF                    \ this is a branch to the next instruction - 
  1534.                         \  maybe we can just omit it altogether.
  1535.         destCDP CDP =  optimize_branches? and
  1536.         IF
  1537.             debug? if
  1538.                 ." ELSE branch over nothing - deleting it" cr
  1539.             then
  1540.  
  1541.         \ we pick up the offset to the original conditional branch and
  1542.         \ subtract 4 since we're deleting this branch.
  1543.         
  1544.             -4
  1545.             branchCDP 2+ w@x branchCDP + 2+
  1546.             w+!
  1547.             -4 ++> CDP  EXIT            \ wipe out the branch, and we're done
  1548.         THEN
  1549.     THEN
  1550.  
  1551. \ now we check if we're branching over another branch.  In this case,
  1552. \  we can get rid of both of them!
  1553.  
  1554.     false -> wipeBoth?
  1555.     offs 8 =  optimize_branches? and
  1556.  
  1557.     IF    branchCDP 4+ w@            \ these are the opcodes for our various
  1558.                                 \  kinds of unconditional branches:
  1559.         CASE[    $ BF02    ],            \ EXIT
  1560.             [    $ BF08    ],            \ normal uncond. branch
  1561.             [    $ BF09    ]=>            \ ELSE-branch
  1562.                 debug? if
  1563.                     ." ELSE branch over another branch - deleting both."  cr
  1564.                     ." Here's the code before we do:" cr
  1565.                     dasm
  1566.                 then
  1567.                 true -> wipeBoth?
  1568.                 
  1569.             DEFAULT=>    drop
  1570.  
  1571.         ]CASE
  1572.     THEN
  1573.  
  1574. \ now if we're compiling the ELSE branch, we resolve it and we're done.
  1575.  
  1576.     wipeBoth?
  1577.     NIF    offs $ FFFFFFFC and                \ %%%%temp while we're testing
  1578.         branchCDP 2+ w!  EXIT
  1579.     THEN
  1580.  
  1581. \ if we got here, we're omitting both the ELSE and the following
  1582. \  branch.
  1583.  
  1584. \ First we pick up the offset to the original conditional branch,
  1585. \ work out where it is, and compute the new offset to put in it,
  1586. \ so that it will branch to the target location of the following
  1587. \ branch, which is where it's going anyway.  Note we must allow
  1588. \ for the removal of the two branches, by reducing the offset by 8.
  1589.             
  1590.     branchCDP 2+ w@x branchCDP + -> condCDP
  1591.     branchCDP 6 + w@            \ offs to target, rel to branchCDP + 4
  1592.     branchCDP condCDP - + 4-     \ new offs, with 8 subtracted
  1593.     condCDP 2+  w!
  1594.  
  1595. \ If there's any code to move, we move it back by 8 bytes.  
  1596. \  ASSERT: there won't be a resolved branch pointing to anywhere in
  1597. \  the middle of the code we're moving!
  1598.  
  1599.     CDP branchCDP 8 + -  -> len
  1600.     len 0>
  1601.     IF    branchCDP 8 + dup 8 -  len  move        \ areas overlap, so don't use
  1602.     THEN                                    \  aligned_move
  1603.     8 --> CDP
  1604. ;
  1605.  
  1606.  
  1607. : RESOLVE_BRANCH  { branchCDP destCDP \ offs -- }
  1608.  
  1609.     branchCDP w@ $ BF09 =  optimize_branches? and
  1610.                                 \ is it an ELSE branch?
  1611.     IF                            \ yes - rather a special case, so we factor it out.
  1612.         branchCDP destCDP  resolve_ELSE  EXIT
  1613.     THEN
  1614.  
  1615.     destCDP branchCDP -  -> offs
  1616.  
  1617.     offs 4 =
  1618.     IF                    \ this is a branch to the next instruction - 
  1619.                         \  maybe we can just omit it altogether.
  1620.         destCDP CDP =  optimize_branches? and
  1621.         IF
  1622.             [ debug? ] [if]
  1623.                 ." conditional branch over nothing - deleting it" cr
  1624.             [then]
  1625.             -4 ++> CDP  EXIT        \ wipe out the branch, and we're done
  1626.         THEN
  1627.     THEN
  1628.  
  1629.     \ we resolve the branch:
  1630.  
  1631.     offs $ FFFFFFFC and                \ &&&&temp while we're testing
  1632.     branchCDP 2+ w!
  1633.  
  1634.     \ now if what we branched over was another branch instruction, we can
  1635.     \  combine them.
  1636.     
  1637.     offs 8 =  optimize_branches? and
  1638.  
  1639.     IF    branchCDP 4+ w@            \ these are the opcodes for our various
  1640.                                     \  kinds of unconditional branches:
  1641.         CASE[    $ BF02    ],            \ EXIT
  1642.             [    $ BF08    ],            \ normal uncond. branch
  1643.             [    $ BF09    ]=>            \ ELSE-branch
  1644.                 debug? if
  1645.                     ." conditional branch over another branch - combining them"  cr
  1646.                         ." here's the code before we do:" cr
  1647.                     dasm
  1648.                 then
  1649.                 branchCDP  combine_branches
  1650.             DEFAULT=>    drop
  1651.         ]CASE
  1652.     THEN
  1653. ;
  1654.  
  1655.  
  1656. : RESOLVE_UNCONDITIONAL_BRANCH  { branchCDP destCDP \ offs -- }
  1657.     \ We only use this for forward definitions and a couple of other
  1658.     \  related things.  So we don't do any fancy optimizations.
  1659.  
  1660.     destCDP branchCDP -  -> offs
  1661.     offs  $ 03FFFFFF and            \ uncond branches have 36-bit offset
  1662.     $ 48000000  or
  1663.     branchCDP !
  1664. [ ppc? ] [if]
  1665.     branchCDP 4  fix_caches
  1666. [then]
  1667. ;
  1668.  
  1669. endload
  1670.  
  1671. \ &&& not currently doing this, since we normally have to do some
  1672. \  register shuffling on return from a call.
  1673.  
  1674. : TAIL_OPTIMIZE?  { \ lookHere inst -- did_it? }
  1675.     false
  1676.     
  1677. \    CDP 4- -> lookHere
  1678. \    lookHere c@ 2 >> 18 =  0EXIT
  1679. \    lookHere @  -> inst
  1680. \    inst 1 and  0EXIT
  1681. \    inst 1 xor  lookHere !
  1682. \    drop true
  1683.  
  1684. ;
  1685.